package org.jeecg.modules.hand;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ByteUtil;
import com.alibaba.fastjson.util.TypeUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.c.entity.*;
import org.jeecg.modules.c.service.*;
import org.jeecg.modules.client.ChannelManager;
import org.jeecg.modules.enmu.AttributeLength;
import org.jeecg.modules.enmu.MessageTypeEnum;
import org.jeecg.modules.utils.SendMessageUtils;
import org.jeecg.modules.vo.Message;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import static org.jeecg.modules.enmu.AttributeLength.CONTENT_START;
import static org.jeecg.modules.enmu.MessageTypeEnum.DYN_ACCESC_MODE_ACK;


@Slf4j
@Component
public class NettyClientHandler extends ChannelInboundHandlerAdapter implements ApplicationContextAware {


    @Autowired
    private IMSCService mSCService;


    @Autowired
    private IMSignalService mSignalService;
    @Autowired
    private IDSignalHService dSignalHService;

    @Autowired
    private IDAlarmHService dAlarmHService;

    @Autowired
    private IDActiveAlarmService dActiveAlarmServic;
    private static ApplicationContext applicationContext;


    /**
     * 管道注册成功
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelRegistered(ctx);
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        super.channelUnregistered(ctx);
    }

    /**
     * 管道激活，激活后将管道暴露出去，让NettyClient类获取管道
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
       log.debug("管道注册成功:");
        super.channelInactive(ctx);
        super.channelActive(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
    }

    /**
     * 处理从服务器返回的消息
     *
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof Message) {
            Message message = (Message) msg;
            int messageType = message.getMessageType();
            byte[] messageContent = message.getMessageContent();
            //作为客户端解析消息内容
            //   parseMessageNews(messageType, messageContent, ctx);
            parseMessageNewsMessage(messageType, message, ctx);
            //  parseMessage(messageType, messageContent, ctx);
        }
        super.channelRead(ctx, msg);
    }

    private void parseMessageNewsMessage(int messageType, Message message, ChannelHandlerContext ctx) {
        MessageTypeEnum messageTypeEnum = MessageTypeEnum.fromValue((int) messageType);
        switch (messageTypeEnum) {
            //用户请求实时数据方式
            case SET_DYN_ACCESC_MODE:
               log.debug("用户请求实时数据方式");
                parseDynAccessModeClient(message, ctx);
                break;
            case SET_ALARM_MODE:
               log.debug("用户设置告警信息等级");
                parseAlarmModeNewMessage(message, ctx);
                break;
        /*    case SEND_ALARM_ACK:
               log.debug("告警信息反馈");
                 parseAlarmModeMessage(message, ctx);
                break;*/
            case SET_POINT:
               log.debug("用户请求写数据动作值");
                //todo 待确认
                //  parseAlarmModeMessage(messageContent, ctx);
                break;
            case MODIFY_PA:
               log.debug("用户请求改口令");
                //todo 待确认
                //  parseModifyPaMessage(messageContent, ctx);
                break;
            case HEART_BEAT:
               log.debug("心跳检测");
                sendHeartAck(ctx, message);
                break;
            case TIME_CHECK_ACK:
               log.debug("时钟同步响应");
                //  sendTimeCheck(ctx, messageContent);
            default:
               log.debug("Unknown message type: " + messageType);
                break;
        }
    }

    /**
     * 告警信息反馈
     * @param message
     * @param ctx
     */
    private void parseAlarmModeMessage(Message message, ChannelHandlerContext ctx) {
    }

    private void parseAlarmModeNewMessage(Message message, ChannelHandlerContext ctx) {
        IMSignalService mSignalService = applicationContext.getBean(IMSignalService.class);
        ByteBuf buffer = message.getBuffer();
        int groupid = buffer.readIntLE();

        try {
            int leave = buffer.readInt();
            //响应模式的数量
            int count = buffer.readIntLE();
            //如果数量是0，则什么也不敢
            if (count == 0) {
                return;
            }
            List<MSignal> dSignalHtotalList = new ArrayList<>();
            //遍历
            for (int i = 0; i < count; i++) {
                //获取设备编号
                byte[] bytes = new byte[AttributeLength.ID_LEN.getLength()];

                buffer.readBytes(bytes);
                String deviceIdStr = new String(bytes);
                deviceIdStr = deviceIdStr.trim();
                //判断是否存在通配符
                if (deviceIdStr.contains("*")) {
                    //去掉通配符后按照有匹配查询进行查询
                    List<MSignal> dSignalHList = mSignalService.getListLike(deviceIdStr.replace("*", ""));
                    dSignalHtotalList.addAll(dSignalHList);
               /* if (CollectionUtil.isEmpty(dSignalHList)) {
                    errorIDs.add(deviceIdStr);
                    //无效监控点
                    errorcnt++;
                } else {
                    totalSignalHList.addAll(dSignalHList);
                }*/
                } else {
                    QueryWrapper<MSignal> dSignalHQueryWrapper = new QueryWrapper<>();
                    dSignalHQueryWrapper.eq("ID", deviceIdStr);
                    MSignal one = mSignalService.getOne(dSignalHQueryWrapper);
                    if (one == null) {
                        //无效监控点
                        //errorIDs.add(deviceIdStr);
                        //errorcnt++;
                       log.debug("未匹配到监控点：" + deviceIdStr);
                    } else {
                        dSignalHtotalList.add(one);
                        //   totalSignalHList.add(one);
                    }

                }
            }
            //得到所有的监控点
            //所有监控点的监控登记
            for (MSignal mSignal : dSignalHtotalList) {
                mSignal.setAlarmlevel(leave);
            }
            //更新信号数据
            mSignalService.updateBatchById(dSignalHtotalList);
            //组装回执
            //全部处理完毕后，发送数据
            Message writeMessage = new Message();

            writeMessage.setMessageType(MessageTypeEnum.ALARM_MODE_ACK.getValue());
            writeMessage.setMessageSerialNo(SendMessageUtils.messageSerialNo);
            //创建一个新的buffer
            ByteBuf buf = Unpooled.buffer();
            buf.writeIntLE(groupid);
            //设置返回结果,1成功，0失败
            buf.writeInt(1);
            writeMessage.setBuffer(buf);
            ctx.channel().writeAndFlush(message);
        } catch (Exception e) {
           log.debug("解析告警信息异常：" + e.getMessage());
            //设置失败
            //全部处理完毕后，发送数据
            Message writeMessage = new Message();
            writeMessage.setMessageType(MessageTypeEnum.ALARM_MODE_ACK.getValue());
            message.setMessageSerialNo(SendMessageUtils.messageSerialNo);
            ByteBuf buf = Unpooled.buffer();
            buf.writeIntLE(groupid);
            //设置返回结果,1成功，0失败
            buf.writeInt(1);
            message.setBuffer(buf);
            ctx.channel().writeAndFlush(message);
        }

    }

    private void sendHeartAck(ChannelHandlerContext ctx, Message message) {
        Message writeMessage = new Message();
        writeMessage.setMessageType(MessageTypeEnum.HEART_BEAT_ACK.getValue());
        ctx.channel().writeAndFlush(writeMessage);


    }

    private void parseDynAccessModeClient(Message message, ChannelHandlerContext ctx) {
        IMSignalService mSignalService = applicationContext.getBean(IMSignalService.class);
        IDSignalHService dSignalHService = applicationContext.getBean(IDSignalHService.class);
        ByteBuf buffer = message.getBuffer();
        // 消息内容为固定格式,直接从第16个字节开始解析到第19个字节结束。
        byte[] scidByte = new byte[AttributeLength.SCID_LEN.getLength()];
        buffer.readBytes(scidByte);
        String scidStr = new String(scidByte);
        scidStr = scidStr.trim();
        //数据包序列号
        int groupid = buffer.readIntLE();
        int mode = buffer.readInt();
        int interval = 0;
        //获取时间间隔
        if (mode == 2) {
            interval = buffer.readIntLE();
        }
        //获取id请求数量
        int idCount = buffer.readIntLE();
        //获取请求数据中的id数量
        log.info("idCount:" + idCount);
        //判断存在几个值
        List<MSignal> totalSignalHList = new ArrayList<>();
        int errorcnt = 0;
        List<String> errorIDs = new ArrayList<>();
        for (int i = 0; i < idCount; i++) {
            //获取设备id
            byte[] idLenByte = new byte[AttributeLength.ID_LEN.getLength()];
            buffer.readBytes(idLenByte);
            String deviceIdStr = new String(idLenByte);
            deviceIdStr = deviceIdStr.trim();
            //判断是否存在通配符
            if (deviceIdStr.contains("*")) {
                //去掉通配符后按照有匹配查询进行查询
                List<MSignal> dSignalHList = mSignalService.getListLike(deviceIdStr.replace("*", ""));
                if (CollectionUtil.isEmpty(dSignalHList)) {
                    errorIDs.add(deviceIdStr);
                    //无效监控点
                    errorcnt++;
                } else {
                    totalSignalHList.addAll(dSignalHList);
                }
            } else {
                QueryWrapper<MSignal> dSignalHQueryWrapper = new QueryWrapper<>();
                dSignalHQueryWrapper.eq("id", deviceIdStr);
                MSignal one = mSignalService.getOne(dSignalHQueryWrapper);
                if (one == null) {
                    //无效监控点
                    errorIDs.add(deviceIdStr);
                    errorcnt++;
                } else {
                    totalSignalHList.add(one);
                }
            }
        }
        if (CollectionUtils.isEmpty(totalSignalHList)) {
            return;
        }
        Date now = new Date();

        for (MSignal mSignal : totalSignalHList) {
            mSignal.setMode(mode);
            if (Objects.equals(mode, 2)) {
                //需要获取时间间隔
                if (interval < 1) {
                    interval = 1;
                }
                mSignal.setPollingTime(interval);
                //设置数据上传时间
            }
            mSignal.setUploadtime(now);
        }
        //设置信号处理模式
        mSignalService.updateBatchById(totalSignalHList);
        //全部处理完毕后，发送数据
        Message messageWrite = new Message();
        messageWrite.setMessageType(DYN_ACCESC_MODE_ACK.getValue());
        messageWrite.setMessageSerialNo(SendMessageUtils.messageSerialNo);
        ByteBuf buf = Unpooled.buffer();
        messageWrite.setBuffer(buf);
        buf.writeBytes(scidByte);
        buf.writeIntLE(groupid);
        //设置成功或者失败标识，1成功，0失败
        buf.writeInt(1);
        if (CollectionUtil.isNotEmpty(totalSignalHList)) {
            buf.writeIntLE(totalSignalHList.size());
        }
        //获取对应信号的最新数据
        List<DSignalH> signalList = dSignalHService.dSignalHService(totalSignalHList);
        //根据信号
        for (DSignalH dSignalH : signalList) {
            //todo  根据数据类型判断是数字量还是模拟量float 数字量long
            buf.writeInt(dSignalH.getType());

            byte[] bytes = SendMessageUtils.padWithSpaces(dSignalH.getScid(), AttributeLength.SCID_LEN.getLength());
            buf.writeBytes(bytes);
            buf.writeFloatLE(dSignalH.getValue());
            buf.writeInt(dSignalH.getStatus());
        }
        //组装无效监控点
        buf.writeIntLE(errorcnt);
        //组装无效监控点id
        for (String errorID : errorIDs) {
            buf.writeBytes(errorID.getBytes());
            byte[] errorIDBytes = SendMessageUtils.padWithSpaces(errorID, AttributeLength.ID_LEN.getLength());
            buf.writeBytes(errorIDBytes);
        }
        //发送已组装数据
        ctx.channel().writeAndFlush(messageWrite);
    }

    private void parseMessageNews(int messageType, byte[] messageContent, ChannelHandlerContext ctx) {
        MessageTypeEnum messageTypeEnum = MessageTypeEnum.fromValue((int) messageType);
        switch (messageTypeEnum) {
            case LOGOUT:
                //返回登出ACK
                Message message = new Message();
                //登录名称
                message.setMessageType(MessageTypeEnum.LOGIN_ACK.getValue());
                //登录序列号
                message.setMessageSerialNo(SendMessageUtils.messageSerialNo);
                ctx.channel().writeAndFlush(message);
                // 处理完登录逻辑后，继续处理其他消息
               log.debug("用户登出确认");
                break;
            //用户请求实时数据方式
            case SET_DYN_ACCESC_MODE:
               log.debug("用户请求实时数据方式");
                parseDynAccessModeClient(messageContent, ctx);
                break;
            case SET_ALARM_MODE:
               log.debug("用户设置告警信息等级");
                parseAlarmModeNewMessage(messageContent, ctx);
                break;
            case SEND_ALARM_ACK:
               log.debug("告警信息反馈");
                //  parseAlarmModeMessage(messageContent, ctx);
                break;
            case SET_POINT:
               log.debug("用户请求写数据动作值");
                //todo 待确认
                //  parseAlarmModeMessage(messageContent, ctx);
                break;
            case MODIFY_PA:
               log.debug("用户请求改口令");
                //todo 待确认
                parseModifyPaMessage(messageContent, ctx);
                break;
            case HEART_BEAT_ACK:
               log.debug("心跳回执");
                sendHeartAck(ctx, messageContent);
                break;
            case TIME_CHECK_ACK:
               log.debug("时钟同步响应");
                sendTimeCheck(ctx, messageContent);
            default:
               log.debug("Unknown message type: " + messageType);
                break;
        }
    }

    private void sendTimeCheck(ChannelHandlerContext ctx, byte[] messageContent) {
        ByteBuffer yearByte = ByteBuffer.wrap(messageContent, AttributeLength.CONTENT_START.getLength(), AttributeLength.SHORT_LENGTH.getLength());
        ByteBuffer monthByte = ByteBuffer.wrap(messageContent, AttributeLength.CONTENT_START.getLength() + AttributeLength.SHORT_LENGTH.getLength(), AttributeLength.CHAR_LENGTH.getLength());
        ByteBuffer dayByte = ByteBuffer.wrap(messageContent, AttributeLength.CONTENT_START.getLength() + AttributeLength.SHORT_LENGTH.getLength() + AttributeLength.CHAR_LENGTH.getLength(), AttributeLength.CHAR_LENGTH.getLength());
        ByteBuffer hourByte = ByteBuffer.wrap(messageContent, AttributeLength.CONTENT_START.getLength() + AttributeLength.SHORT_LENGTH.getLength() + AttributeLength.CHAR_LENGTH.getLength() * 2, AttributeLength.CHAR_LENGTH.getLength());
        ByteBuffer minuteByte = ByteBuffer.wrap(messageContent, AttributeLength.CONTENT_START.getLength() + AttributeLength.SHORT_LENGTH.getLength() + AttributeLength.CHAR_LENGTH.getLength() * 3, AttributeLength.CHAR_LENGTH.getLength());
        ByteBuffer secondByte = ByteBuffer.wrap(messageContent, AttributeLength.CONTENT_START.getLength() + AttributeLength.SHORT_LENGTH.getLength() + AttributeLength.CHAR_LENGTH.getLength() * 4, AttributeLength.CHAR_LENGTH.getLength());
        String year = new String(yearByte.array());
        String month = new String(monthByte.array());
        String day = new String(dayByte.array());
        String hour = new String(hourByte.array());
        String minute = new String(minuteByte.array());
        String second = new String(secondByte.array());
        String time = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
       log.debug("时钟同步响应时间：" + time);
        String date = year + month + day + " " + hour + ":" + minute + ":" + second;
        String command = "sudo date --set=\"" + date + "\"";
        String result = "1";
        try {
            Process process = Runtime.getRuntime().exec(command);
            process.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
           log.debug("时钟同步失败");
            result = "0";

        }
        Message message = new Message();
        message.setMessageType(MessageTypeEnum.TIME_CHECK_ACK.getValue());
        message.setMessageSerialNo(SendMessageUtils.messageSerialNo);
        byte[] bytes = SendMessageUtils.padWithSpaces(result, AttributeLength.LONG_LENGTH.getLength());
        message.setMessageContent(bytes);
        ctx.channel().writeAndFlush(message);
    }

    private void parseModifyPaMessage(byte[] messageContent, ChannelHandlerContext ctx) {
        ByteBuffer userNameByte = ByteBuffer.wrap(messageContent, AttributeLength.CONTENT_START.getLength(), AttributeLength.LONG_LENGTH.getLength());
        String userNameStr = new String(userNameByte.array());
        userNameStr = userNameStr.trim();
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("user", userNameStr);
        MSC one = mSCService.getOne(wrapper);
        if (one == null) {
           log.debug("用戶不存在");
            Message message = new Message();
            message.setMessageType(MessageTypeEnum.MODIFY_PA_ACK.getValue());
            message.setMessageSerialNo(SendMessageUtils.messageSerialNo);
            byte[] bytes = SendMessageUtils.padWithSpaces("0", AttributeLength.LONG_LENGTH.getLength());
            message.setMessageContent(bytes);
            ctx.channel().writeAndFlush(message);
            return;
        }
        String password = new String(messageContent, AttributeLength.CONTENT_START.getLength() + AttributeLength.USER_LENGTH.getLength(), AttributeLength.PASSWORD_LEN.getLength());
        password = password.trim();
        if (!password.equals(one.getPassword())) {
           log.debug("密码错误");
            Message message = new Message();
            message.setMessageType(MessageTypeEnum.MODIFY_PA_ACK.getValue());
            message.setMessageSerialNo(SendMessageUtils.messageSerialNo);
            byte[] bytes = SendMessageUtils.padWithSpaces("0", AttributeLength.LONG_LENGTH.getLength());
            message.setMessageContent(bytes);
            ctx.channel().writeAndFlush(message);
            return;
        }
        String newPassword = new String(messageContent, AttributeLength.CONTENT_START.getLength() + AttributeLength.USER_LENGTH.getLength() + AttributeLength.PASSWORD_LEN.getLength(), AttributeLength.PASSWORD_LEN.getLength());
        newPassword = newPassword.trim();
        one.setPassword(newPassword);
        mSCService.updateById(one);
        Message message = new Message();
        message.setMessageType(MessageTypeEnum.MODIFY_PA_ACK.getValue());
        message.setMessageSerialNo(SendMessageUtils.messageSerialNo);
        byte[] bytes = SendMessageUtils.padWithSpaces("1", AttributeLength.LONG_LENGTH.getLength());
        message.setMessageContent(bytes);
        ctx.channel().writeAndFlush(message);


    }

    private void parseAlarmModeNewMessage(byte[] messageContent, ChannelHandlerContext ctx) {
        ByteBuffer groupidByte = ByteBuffer.wrap(messageContent, AttributeLength.CONTENT_START.getLength(), AttributeLength.LONG_LENGTH.getLength());
        String groupidStr = new String(groupidByte.array());
        groupidStr = groupidStr.trim();
        Long groupid = Long.valueOf(groupidStr);
        try {
            ByteBuffer modeByte = ByteBuffer.wrap(messageContent, CONTENT_START.getLength() + AttributeLength.LONG_LENGTH.getLength(), AttributeLength.LONG_LENGTH.getLength());
            String modeStr = new String(modeByte.array());
            modeStr = modeStr.trim();
            Long leave = Long.valueOf(modeStr);
            //告警登录
            ByteBuffer byteCount = ByteBuffer.wrap(messageContent, CONTENT_START.getLength() + AttributeLength.LONG_LENGTH.getLength() * 2, AttributeLength.LONG_LENGTH.getLength());
            String countStr = new String(byteCount.array());
            countStr = countStr.trim();
            Long count = Long.valueOf(countStr);
            //如果数量是0，则什么也不敢
            if (count == 0) {
                return;
            }
            List<MSignal> dSignalHtotalList = new ArrayList<>();
            //遍历
            for (int i = 0; i < count; i++) {
                //获取设备编号
                ByteBuffer IdCount = ByteBuffer.wrap(messageContent, CONTENT_START.getLength() + AttributeLength.LONG_LENGTH.getLength() * 3 + AttributeLength.ID_LEN.getLength() * i, AttributeLength.ID_LEN.getLength());
                String deviceIdStr = new String(IdCount.array());
                deviceIdStr = deviceIdStr.trim();
                //判断是否存在通配符
                if (deviceIdStr.contains("*")) {
                    //去掉通配符后按照有匹配查询进行查询
                    List<MSignal> dSignalHList = mSignalService.getListLike(deviceIdStr.replace("*", ""));
                    dSignalHtotalList.addAll(dSignalHList);
               /* if (CollectionUtil.isEmpty(dSignalHList)) {
                    errorIDs.add(deviceIdStr);
                    //无效监控点
                    errorcnt++;
                } else {
                    totalSignalHList.addAll(dSignalHList);
                }*/
                } else {
                    QueryWrapper<MSignal> dSignalHQueryWrapper = new QueryWrapper<>();
                    dSignalHQueryWrapper.eq("ID", deviceIdStr);
                    MSignal one = mSignalService.getOne(dSignalHQueryWrapper);
                    if (one == null) {
                        //无效监控点
                        //errorIDs.add(deviceIdStr);
                        //errorcnt++;
                       log.debug("未匹配到监控点：" + deviceIdStr);
                    } else {
                        dSignalHtotalList.add(one);
                        //   totalSignalHList.add(one);
                    }

                }
            }
            //得到所有的监控点
            //所有监控点的监控登记
            for (MSignal mSignal : dSignalHtotalList) {
                mSignal.setAlarmlevel(leave);
            }
            //更新信号数据
            mSignalService.updateBatchById(dSignalHtotalList);
            //组装回执
            //全部处理完毕后，发送数据
            Message message = new Message();
            message.setMessageType(MessageTypeEnum.ALARM_MODE_ACK.getValue());
            message.setMessageSerialNo(SendMessageUtils.messageSerialNo);
            ByteBuffer byteBuffer = ByteBuffer.allocate(AttributeLength.LONG_LENGTH.getLength() * 2);
            byte[] groupByte = SendMessageUtils.padWithSpaces(groupid + "", AttributeLength.LONG_LENGTH.getLength());
            byte[] resultbytes = SendMessageUtils.padWithSpaces("1", AttributeLength.LONG_LENGTH.getLength());
            byteBuffer.put(groupByte);
            byteBuffer.put(resultbytes);
            message.setMessageContent(byteBuffer.array());
            ctx.channel().writeAndFlush(message);
        } catch (Exception e) {
           log.debug("解析告警信息异常：" + e.getMessage());
            //设置失败
            //全部处理完毕后，发送数据
            Message message = new Message();
            message.setMessageType(MessageTypeEnum.ALARM_MODE_ACK.getValue());
            message.setMessageSerialNo(SendMessageUtils.messageSerialNo);
            ByteBuffer byteBuffer = ByteBuffer.allocate(AttributeLength.LONG_LENGTH.getLength() * 2);
            byte[] groupByte = SendMessageUtils.padWithSpaces(groupid + "", AttributeLength.LONG_LENGTH.getLength());
            byte[] resultbytes = SendMessageUtils.padWithSpaces("0", AttributeLength.LONG_LENGTH.getLength());
            byteBuffer.put(groupByte);
            byteBuffer.put(resultbytes);
            message.setMessageContent(byteBuffer.array());
            ctx.channel().writeAndFlush(message);
        }


    }

    /**
     * 接收实时数据发送的方式
     *
     * @param messageContent
     * @param ctx
     */
    private void parseDynAccessModeClient(byte[] messageContent, ChannelHandlerContext ctx) {
        //根据
        // 消息内容为固定格式,直接从第16个字节开始解析到第19个字节结束。
        ByteBuffer scid = ByteBuffer.wrap(messageContent, AttributeLength.CONTENT_START.getLength(), AttributeLength.SCID_LEN.getLength());
        String scidStr = new String(scid.array());
        scidStr = scidStr.trim();
        ByteBuffer groupidByte = ByteBuffer.wrap(messageContent, AttributeLength.CONTENT_START.getLength() + AttributeLength.SCID_LEN.getLength(), AttributeLength.LONG_LENGTH.getLength());
        String groupidStr = new String(scid.array());
        groupidStr = groupidStr.trim();
        Long groupid = Long.valueOf(groupidStr);
        ByteBuffer modeByte = ByteBuffer.wrap(messageContent, AttributeLength.CONTENT_START.getLength() + AttributeLength.SCID_LEN.getLength() * 2, AttributeLength.LONG_LENGTH.getLength());
        String modeStr = new String(scid.array());
        modeStr = modeStr.trim();
        //获取请求数据中的id数量
        ByteBuffer idCountByte = ByteBuffer.wrap(messageContent, AttributeLength.CONTENT_START.getLength() + AttributeLength.SCID_LEN.getLength() + AttributeLength.LONG_LENGTH.getLength() * 4, AttributeLength.LONG_LENGTH.getLength());
        String idCountStr = new String(idCountByte.array());
        idCountStr = idCountStr.trim();
        Long idCount = Long.valueOf(idCountStr);
        //判断存在几个值
        List<MSignal> totalSignalHList = new ArrayList<>();
        int errorcnt = 0;
        List<String> errorIDs = new ArrayList<>();

        for (int i = 0; i < idCount; i++) {
            //获取设备id
            ByteBuffer idLenByte = ByteBuffer.wrap(messageContent, AttributeLength.CONTENT_START.getLength() + AttributeLength.SCID_LEN.getLength() + AttributeLength.LONG_LENGTH.getLength() * 5 + AttributeLength.ID_LEN.getLength() * i, AttributeLength.ID_LEN.getLength());
            String deviceIdStr = new String(idLenByte.array());
            deviceIdStr = deviceIdStr.trim();
            //判断是否存在通配符
            if (deviceIdStr.contains("*")) {
                //去掉通配符后按照有匹配查询进行查询
                List<MSignal> dSignalHList = mSignalService.getListLike(deviceIdStr.replace("*", ""));

                if (CollectionUtil.isEmpty(dSignalHList)) {
                    errorIDs.add(deviceIdStr);
                    //无效监控点
                    errorcnt++;
                } else {
                    totalSignalHList.addAll(dSignalHList);
                }
            } else {
                QueryWrapper<MSignal> dSignalHQueryWrapper = new QueryWrapper<>();
                dSignalHQueryWrapper.eq("ID", deviceIdStr);
                MSignal one = mSignalService.getOne(dSignalHQueryWrapper);
                if (one == null) {
                    //无效监控点
                    errorIDs.add(deviceIdStr);
                    errorcnt++;
                } else {
                    totalSignalHList.add(one);
                }

            }

        }
        if (CollectionUtils.isEmpty(totalSignalHList)) {
            return;
        }
        Date now = new Date();

        for (MSignal mSignal : totalSignalHList) {
            mSignal.setMode(TypeUtils.castToInt(modeStr));
            if ("2".equals(modeStr)) {
                //需要获取时间间隔
                String intervalStr = new String(scid.array());
                intervalStr = intervalStr.trim();
                Integer pollingTime = Integer.valueOf(intervalStr);
                if (pollingTime < 1) {
                    pollingTime = 1;
                }
                mSignal.setPollingTime(pollingTime);
                //设置数据上传时间
            }
            mSignal.setUploadtime(now);
        }
        //设置信号处理模式
        mSignalService.updateBatchById(totalSignalHList);
        //全部处理完毕后，发送数据
        Message message = new Message();
        message.setMessageType(DYN_ACCESC_MODE_ACK.getValue());
        message.setMessageSerialNo(SendMessageUtils.messageSerialNo);
        byte[] terminalIDByte = SendMessageUtils.padWithSpaces(scidStr, AttributeLength.SCID_LEN.getLength());
        //生成随机数，保持在int范围内，并且是正数
        int randomNum = (int) (Math.random() * 100000000);
        //设置result
        byte[] resultBytes = SendMessageUtils.padWithSpaces("1", AttributeLength.LONG_LENGTH.getLength());
        byte[] GroupIDbytes = SendMessageUtils.padWithSpaces(randomNum + "", AttributeLength.LONG_LENGTH.getLength());
        byte[] dataCntBytes = SendMessageUtils.padWithSpaces("0", AttributeLength.LONG_LENGTH.getLength());
        if (CollectionUtil.isNotEmpty(totalSignalHList)) {
            dataCntBytes = SendMessageUtils.padWithSpaces(totalSignalHList.size() + "", AttributeLength.LONG_LENGTH.getLength());
        }
        //获取对应信号的最新数据
        List<DSignalH> signalList = dSignalHService.dSignalHService(totalSignalHList);
        ByteBuffer content = ByteBuffer.allocate(AttributeLength.SCID_LEN.getLength() + AttributeLength.LONG_LENGTH.getLength() * 3 + AttributeLength.AD_AT.getLength() * signalList.size()
                + AttributeLength.LONG_LENGTH.getLength() + AttributeLength.LONG_LENGTH.getLength() * errorcnt
        );
        content.put(terminalIDByte).put(GroupIDbytes).put(resultBytes).put(dataCntBytes);
        //根据信号
        for (DSignalH dSignalH : signalList) {
            //根据数据类型判断如何发送数据，开始拼TA
            byte[] typeBate = SendMessageUtils.padWithSpaces(dSignalH.getType() + "", AttributeLength.ENUM_LENGTH.getLength());
            byte[] idByte = SendMessageUtils.padWithSpaces(dSignalH.getId(), AttributeLength.ID_LEN.getLength());
            byte[] valueByte = SendMessageUtils.padWithSpaces(dSignalH.getValue() + "", AttributeLength.FLOAT_LENGTH.getLength());
            byte[] statusytes = SendMessageUtils.padWithSpaces(dSignalH.getStatus() + "", AttributeLength.ENUM_LENGTH.getLength());
            content.put(typeBate).put(idByte).put(valueByte).put(statusytes);
        }
        //组装无效监控点
        byte[] errorBytes = SendMessageUtils.padWithSpaces(errorcnt + "", AttributeLength.LONG_LENGTH.getLength());
        content.put(errorBytes);
        //组装无效监控点id
        for (String errorID : errorIDs) {
            byte[] errorIDBytes = SendMessageUtils.padWithSpaces(errorID, AttributeLength.ID_LEN.getLength());
            content.put(errorIDBytes);
        }
        //发送已组装数据
        ctx.channel().writeAndFlush(content);


    }

    //作为客户端，开始进行消息传送逻辑


    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        super.userEventTriggered(ctx, evt);
    }

    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
        super.channelWritabilityChanged(ctx);
    }

    /**
     * 异常处理
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
    }

    private void parseMessage(int messageType, byte[] messageContent, ChannelHandlerContext ctx) {
        MessageTypeEnum messageTypeEnum = MessageTypeEnum.fromValue((int) messageType);
        switch (messageTypeEnum) {
            case LOGIN_ACK: // 假设1表示登录响应
                parseLoginResponse(messageContent, ctx);
                break;
            //用户登出确认
            case LOGOUT_ACK:
                parseLoginOutResponse(messageContent, ctx);
               log.debug("用户登出确认");
                break;
            //用户请求实时数据方式
            case DYN_ACCESC_MODE_ACK:
               log.debug("用户请求实时数据方式");
                parseDynAccessMode(messageContent, ctx);
                break;
            case SEND_ALARM:
               log.debug("用户请求告警信息响应");
                parseAlarmMessage(messageContent, ctx);
                break;
            case ALARM_MODE_ACK:
                parseAlarmModeMessage(messageContent, ctx);
                break;
            case HEART_BEAT_ACK:
               log.debug("心跳回执");
                sendHeartAck(ctx, messageContent);
                break;
            case TIME_CHECK_ACK:
               log.debug("时钟同步响应");
                sendTimeAck(ctx, messageContent);
            default:
               log.debug("Unknown message type: " + messageType);
                break;
        }
    }

    private void sendTimeAck(ChannelHandlerContext ctx, byte[] messageContent) {
        byte[] bytes = new byte[AttributeLength.LONG_LENGTH.getLength()];
        System.arraycopy(messageContent, CONTENT_START.getLength(), bytes, 0, AttributeLength.LONG_LENGTH.getLength());
        long time = ByteBuffer.wrap(bytes).getLong();
        if (Objects.equals(time, 0)) {
           log.debug("时钟同步失败");
        } else {
           log.debug("时钟同步成功");
        }
    }

    private void sendHeartAck(ChannelHandlerContext ctx, byte[] messageContent) {

        //更新对应通道的心跳的回执时间zzzzl
        String scid = ctx.channel().attr(ChannelManager.SCID).get();
        mSCService.update().eq("scid", scid).set("head_ack", new Date()).update();

    }


    private void parseAlarmModeMessage(byte[] messageContent, ChannelHandlerContext ctx) {
        byte[] bytes = new byte[AttributeLength.LONG_LENGTH.getLength()];
        System.arraycopy(messageContent, CONTENT_START.getLength(), bytes, 0, AttributeLength.LONG_LENGTH.getLength());
        int result = ByteBuffer.wrap(bytes).getInt();
        if (result == 0) {
           log.debug("设置告警方式失败");
        } else {
           log.debug("设置告警方式成功");
        }


    }

    private void parseAlarmMessage(byte[] messageContent, ChannelHandlerContext ctx) {
        //获取告警数量

        byte[] bytes = new byte[AttributeLength.LONG_LENGTH.getLength()];
        System.arraycopy(messageContent, CONTENT_START.getLength(), bytes, 0, 4);
        int count = ByteBuffer.wrap(bytes).getInt();
        if (count != 0) {
           log.debug("告警数量：" + count);
            for (int i = 1; i <= count; i++) {
                //获取告警数据
                byte[] data = new byte[69];
                System.arraycopy(messageContent, 20 + i * 69, data, 0, 69);
                parseAlarmData(data);
            }
            //接收到实时告警，返回确认
            sendAlarmAck(ctx, messageContent);
        }

    }

    private void sendAlarmAck(ChannelHandlerContext ctx, byte[] messageContent) {
        //组装发送报文
        Message loginMessage = new Message();
        //设置命令
        loginMessage.setMessageType(MessageTypeEnum.SEND_ALARM_ACK.getValue());
        //设置序列号
        loginMessage.setMessageSerialNo(0x11);
        //
        ctx.channel().writeAndFlush(loginMessage);


    }

    /**
     * 解析告警信息
     *
     * @param data
     */
    private void parseAlarmData(byte[] data) {
        //0到10为序号
        DActiveAlarm dActiveAlarm = new DActiveAlarm();
        byte[] bytes = new byte[10];
        System.arraycopy(data, 0, bytes, 0, 10);
        String secno = new String(bytes);
       log.debug("序号：" + secno);
        //10位到46位，为标识号
        byte[] idBytes = new byte[36];
        System.arraycopy(data, 10, idBytes, 0, 36);
        //唯一标识符号
        String id = new String(idBytes);
        //46位到65位为告警时间
        byte[] timeBytes = new byte[19];
        System.arraycopy(data, 46, timeBytes, 0, 19);
        String time = new String(timeBytes);
       log.debug("告警时间：" + time);
        //65到69位为告警等级
        byte[] levelBytes = new byte[4];
        System.arraycopy(data, 65, levelBytes, 0, 4);
        String level = new String(levelBytes);
        // 69位到73位为告警标志
        byte[] flagBytes = new byte[4];
        System.arraycopy(data, 69, flagBytes, 0, 4);
        String flag = new String(flagBytes);
        //73位到77位为告触发值
        byte[] valueBytes = new byte[4];
        System.arraycopy(data, 73, valueBytes, 0, 4);
        String value = new String(valueBytes);
        //77为位到60位，为告警描述
        byte[] descBytes = new byte[60];
        System.arraycopy(data, 77, descBytes, 0, 60);
        String desc = new String(descBytes);
        //告警数据
        //根据标识获取信息对象
        MSignal signal = mSignalService.getById(id);
        dActiveAlarm.setDeviceid(signal.getDeviceid());
        dActiveAlarm.setSerialno(secno);
        dActiveAlarm.setScid(signal.getScid());
        dActiveAlarm.setSiteid(signal.getSiteid());
        dActiveAlarm.setType(signal.getType());
        dActiveAlarm.setSignalname(signal.getSignalname());
        dActiveAlarm.setId(id);
        dActiveAlarm.setAlarmtime(time);
        dActiveAlarm.setAlarmstatus(flag);
        dActiveAlarm.setSynno(Integer.parseInt(secno));
        dActiveAlarm.setAlarmlevel(level);
        dActiveAlarm.setAlarmdesc(desc);
        dActiveAlarm.setAlarmvalue(Float.parseFloat(value));
        dActiveAlarmServic.save(dActiveAlarm);


    }

    private void parseDynAccessMode(byte[] messageContent, ChannelHandlerContext ctx) {
        //获取24个字节到28个字节的数据
        byte[] bytes = new byte[4];
        System.arraycopy(messageContent, 24, bytes, 0, 4);
        int result = ByteBuffer.wrap(bytes).getInt();
        if (result == 0) {
           log.debug("实时数据响应失败");
        }
        if (result == 1) {
           log.debug("实时数据响应成功");
            //解析实时数据个数
            byte[] cnt = new byte[4];
            System.arraycopy(messageContent, 28, cnt, 0, 4);
            //判返回正确数据值的数量
            int count = ByteBuffer.wrap(cnt).getInt();
           log.debug("实时数据个数：" + count);
            //计算总数据总长度，一个完整值为36字节
            int totalLength = count * 44;
           log.debug("实时数据总长度：" + totalLength);
            //从28个字节开始，每32字节为一条数据，从第32个字节开始，到第totalLength个字节结束
            for (int i = 1; i <= count; i++) {
                byte[] data = new byte[44];
                System.arraycopy(messageContent, 44 * i, data, 0, 44);
                //解析数据data数据
                parseTArgetData(data);
            }
        }
    }

    private void parseTArgetData(byte[] data) {
        DSignalH dSignalH = new DSignalH();
        //解析数据类型，0-4个字节
        byte[] typeBytes = new byte[4];
        System.arraycopy(data, 0, typeBytes, 0, 4);
        int type = ByteBuffer.wrap(typeBytes).getInt();
        dSignalH.setType(type);
       log.debug("数据类型：" + type);
        //解析监控标识号，32个字节
        byte[] monitorIdBytes = new byte[36];
        System.arraycopy(data, 4, monitorIdBytes, 0, 36);
        String monitorId = new String(monitorIdBytes);
       log.debug("监控标识号：" + monitorId);
        dSignalH.setId(monitorId);
        //数据值
        byte[] valueBytes = new byte[4];
        System.arraycopy(data, 36, valueBytes, 0, 4);
        float value = ByteBuffer.wrap(valueBytes).getFloat();
       log.debug("数据值：" + value);
        dSignalH.setValue(value);
        //状态
        byte[] statusBytes = new byte[4];
        System.arraycopy(data, 40, statusBytes, 0, 4);
        int status = ByteBuffer.wrap(statusBytes).getInt();
        MSignal mSignal = mSignalService.getById(monitorId);
        dSignalH.setScid(mSignal.getScid());
        dSignalH.setDeviceid(mSignal.getDeviceid());
        dSignalH.setSiteid(mSignal.getSiteid());
        dSignalH.setStatus(status);
        dSignalHService.save(dSignalH);
       log.debug("状态：" + status);

    }

    private void parseLoginOutResponse(byte[] messageContent, ChannelHandlerContext ctx) {
        //将登录权限设置到管道变量中
        ctx.channel().attr(ChannelManager.loginAuth).remove();
        //关闭通道
        ctx.close();

    }

    private void parseLoginResponse(byte[] messageContent, ChannelHandlerContext ctx) {
        // 消息内容为固定格式,直接从第16个字节开始解析到第19个字节结束。
        int authResult = ByteBuffer.wrap(messageContent, 16, 4).getInt();
        //将登录权限设置到管道变量中
        ctx.channel().attr(ChannelManager.loginAuth).set(String.valueOf(authResult));


    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (NettyClientHandler.applicationContext == null) {
            NettyClientHandler.applicationContext = applicationContext;
        }
    }
}
